package xfuzzy.xfghl.codification;

/**
 * Clase que comprueba si existen errores en un cromosoma
 * @author Alberto David Fernandez Fernandez
 * */

public class ChromosomeTester {
	
	// Comprobaciones que se deben hacer:
	// 1. Que el numero de variables sea el adecuado 
	// 2. Que no haya variables repetidas
	// 3. Que el numero de modulos sea el adecuado
	// 4. Que la codifcacion empiece por '-'
	// 5. Que la codifcacion acabe por '++'
	// 6. Que la codificacion sea valida
	
	/**
	 * Metodo que comprueba si un cromosoma es correcto
	 * @param cromosoma Cromosoma a comprobar
	 * @return Devuelve un tipo TypeErrorChromosome si no es valido, null si es valido
	 * */
	
	public static TypeErrorChromosome isValid(DoubleChromosome cromosoma)  {
		
		if (ChromosomeTester.checkError1(cromosoma))
			return TypeErrorChromosome.ERROR1;
		
		if (ChromosomeTester.checkError2(cromosoma))
			return TypeErrorChromosome.ERROR2;
		
		if (ChromosomeTester.checkError3(cromosoma))
			return TypeErrorChromosome.ERROR3;
		
		if (ChromosomeTester.checkError4(cromosoma))
			return TypeErrorChromosome.ERROR4;
		
		if (ChromosomeTester.checkError5(cromosoma))
			return TypeErrorChromosome.ERROR5;
		
		if (ChromosomeTester.checkError6(cromosoma))
			return TypeErrorChromosome.ERROR6;
		
		return null;
	}
	
	/**
	 * Metodo que comprueba un determinado tipo de error en un cromosoma
	 * @param error Enum que indica el tipo de error que se desea comprobar
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe el tipo de error indicado, False en caso contrario
	 * */
	
	public static boolean checkError(TypeErrorChromosome error, DoubleChromosome cromosoma)  {
		
		if (error == TypeErrorChromosome.ERROR1)
			return ChromosomeTester.checkError1(cromosoma);
		else if (error == TypeErrorChromosome.ERROR2)
			return ChromosomeTester.checkError2(cromosoma);
		else if (error == TypeErrorChromosome.ERROR3)
			return ChromosomeTester.checkError3(cromosoma);
		else if (error == TypeErrorChromosome.ERROR4)
			return ChromosomeTester.checkError4(cromosoma);
		else if (error == TypeErrorChromosome.ERROR5)
			return ChromosomeTester.checkError5(cromosoma);
		else
			return ChromosomeTester.checkError6(cromosoma);
	}
	
	/**
	 * Metodo que comprueba que un cromosoma tenga un numero adecuado de variables en la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe error, False en caso contrario
	 * */
	
	private static boolean checkError1(DoubleChromosome cromosoma)  {
		
		// 1. Que el numero de variables en la estructura sea el adecuado
		char [] estructura = cromosoma.getEstructura();
		int contador = 0;
		for (int i = 0; i < estructura.length; i++)
			 if (estructura[i] == EncodingSymbols.variableSymbol)
				 contador++;
				
		if (contador > cromosoma.getNumVariables())  {
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo que comprueba que un cromosoma tenga variables repetidas en la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe error, False en caso contrario
	 * */
	
	private static boolean checkError2(DoubleChromosome cromosoma)  {
		
		// 2. Que no haya variables repetidas
		int [] variables = cromosoma.getVariables();
		for (int i = 0; i < variables.length; i++)  {
			 for (int j = 0; j < variables.length; j++)  {
				  if ((variables[i] == variables[j]) && (i != j))  {
					  return true; 
				  }
			 }
		}
		return false;
	}
	
	/**
	 * Metodo que comprueba que un cromosoma tenga un numero adecuado de modulos en la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe el error, False en caso contrario
	 * */
	
	private static boolean checkError3(DoubleChromosome cromosoma)  {
		
		//3. Que el numero de modulos sea el adecuado
		int contador = 0;
		char [] estructura = cromosoma.getEstructura();
		for (char simbolo : estructura)
			 if (simbolo == EncodingSymbols.moduleSymbol)
				 contador++;
		
		if (contador > cromosoma.getNumModulos())  {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Metodo que comprueba si existe un error en el inicio de la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe el error, False en caso contrario
	 * */
	
	private static boolean checkError4(DoubleChromosome cromosoma)  {
		
		//4. Que la codifcacion empiece por '-'
		String str_aux = String.copyValueOf(cromosoma.getEstructura());
		if (!str_aux.startsWith(EncodingSymbols.startCodification))  {
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo que comprueba si existe un error en el final de la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe el error, False en caso contrario
	 * */
	
	private static boolean checkError5(DoubleChromosome cromosoma)  {
		
		// 5. Que la codifcacion acabe por '++'
		String str_aux = String.copyValueOf(cromosoma.getEstructura());
		if (!str_aux.endsWith(EncodingSymbols.endCodification))  {
			return true;
		}
		return false;
	}
	
	/**
	 * Metodo que comprueba si existe un error en la estructura de la codificacion
	 * @param cromosoma Cromosoma a comprobar
	 * @return True si existe el error, False en caso contrario
	 * */
	
	private static boolean checkError6(DoubleChromosome cromosoma)  {
		
		// 6. Estructura invalida
		int contador = 2;
		char [] estructura = cromosoma.getEstructura();
		for (int i = 1; i < estructura.length; i++)  {
			 if (estructura[i] == EncodingSymbols.moduleSymbol)
				 contador++;
			 if (estructura[i] == EncodingSymbols.variableSymbol)
				 contador--;
			 if ((contador == 0) && (i != estructura.length - 1))  {
				 return true;
			 }
		}
		return false;
	}
}
